I would like to add a level of security to certain buttons in my Perspective project. For example, make a button click-able only if you are part of the Supervisor group. I have created a handful of users and roles under Config>Security>Users, Roles>default, but those roles do not appear in the Designer. I right click on a button and select Configure Event, then OnClick, then Security Settings, but the roles created in the Gateway to not appear.
Under Project Properties>Project>General I have the User source set to "default" which matches my User source in my Gateway.
What am I missing here?
Thank you
Do they show up if you look in the Config/Security Levels
of your gateway webpage? IIRC those are a separate piece you need to configure.
Edit: Whoops, didn't read the question all the way through. Still applicable for disabling buttons.
Make a binding on the enabled
property of the button that uses isAuthorized
to check the logged in users security level.
Make sure you've defined security levels with names that match your role names under config>security>security levels
Alternatively, you could create a property binding (bound to the session "authenticated" property) on the "enabled" property of your button or whatever component you want and add a script transform that looks like this:
def transform(self, value, quality, timestamp):
def is_user_member_of_roles(user_roles, auth_roles):
"""Returns True or False based on the user's membership in a list of roles.
Args:
user_roles (str or list[str]): A role name or list of role names to check.
auth_roles (str or list[str]): The current user's role or list of roles.
Returns:
bool: True if the user has any of the roles in `user_roles`, otherwise False.
"""
user_roles = list(user_roles) if isinstance(user_roles, list) else [str(user_roles)]
auth_roles = list(auth_roles) if isinstance(auth_roles, list) else [str(auth_roles)]
for user_role in user_roles:
for auth_role in auth_roles:
if user_role == auth_role:
return True
return False
if self.session.props.auth.authenticated:
return True if is_user_member_of_roles(list(self.session.props.auth.user.roles), ["Role1", "Role2"]) else False
return False
This is it, per the manual:
Adding or modifying a role in the Security Levels section of the Gateway will not impact or change roles located in the Users, Roles section, as they are separate entities within Ignition. You will need to update the roles in the Users, Roles section separately from the roles in Security Levels.
One thing I've done in Vision recently that could be replicated in Perspective is to create client tags (or perspective session custom properties) that are bound to the various permission levels. So these are just boolean properties/vision client tags that in Vision uses the hasRole()
function, but in perspective could use the isAuthorized()
function. Then anywhere you need to check authorization for anything you can just bind it directly to that custom property or use an expression to check multiple levels depending on the need. Plus, I think it looks cleaner that it's evaluated once at the session level and then just bound everywhere to the result.
Edit: Bonus is that if you ever rework/rename any levels, you only have to change it in one place.
Hey Ryan,
I configured the security settings for the onClick event to be Managers only. But the button still works as if it was public. I don't have to be logged in to click it during runtime.
It does have this syntax error from some automatically populated syntax. Not sure if I need this, but I can't delete it.
I have created my roles in both "Users, roles" and in "Security Levels". Do I need to somehow link these Security Levels to the Roles? Seems odd to me that you create the same Role/Security Level name in two places and the Gateway just knows to connect the two. If that's how it works, great. But something is not right in my case.
That's not a button but rather the link component. Your script will give an access denied when you click but the link component will then also navigate to your url. Consider using a button instead and a script on action performed with system.perspective.navigate('/100 Conc Line 1')
then set the script security to the roles you want.
Personally, I just use a binding on the enable property and use session properties like @michael.flagler suggests. Added benefit is that your users can visually tell that its disabled.